/*
 *      Read IdeAta, IdeLow, IdeDebug and IdeTimer comments for better
 *      understand how this driver works.
 *      Implementing new ide commands is very very simple.
 *      All the major part of the Ata protocol is in "IdeAta.c".
 *      You only need to look for Ata-4 references, search for a
 *      command and see what protocol and what parameter you have
 *      to use.
 *      I have written specific subroutines to read, write and identify
 *      identifying devices, but they only simplify the interface for
 *      the more generic ata protocol.
 *
 *      I have already set inizialization of Ide Driver in main.c so
 *      you only need to:
 *        select the channel you want to use (with SelectAtaChannel);
 *        check CurrentChannel to find a specific device (directly
 *      with CurrentChannel var);
 *        use one of the specific command sub (i.e. ReadSectorLba,
 *      WriteSectorLba, ...)
 */

#include "../../include/types.h"
#include "../../include/const.h"
#include "../../include/isr.h"
#include "../../include/string.h"
#include "../../include/mem.h"
#include "../../include/idetimer.h"
#include "../../include/idelow.h"
#include "../../include/monitor.h"
#include "../../include/ideata.h"
#include "../../include/keyboard.h"
#include "../../include/ide.h"

extern IdeChannel_Struct * CurrentChannel;


void ShowDeviceSubData(int Dev){
  Device_Struct * CurDev=&CurrentChannel->Device[Dev];

  if(CurDev->Type==CC_DEVTYPE_ATA){
    monitor_write("\n\rDevice ");
    monitor_write_dec(Dev);
    monitor_write(": ");
    monitor_write(CurDev->Info.ModelNumber);
    monitor_write("\n\r    Type: ATA ");
    monitor_write_dec(CurDev->Info.HighestAtaSupported);
    monitor_write(" - UDMA ");
    monitor_write_dec(CurDev->Info.HighestUDMASupported);
    monitor_write("\n\r    Firmware Rev: ");
    monitor_write(CurDev->Info.FirmwareRev);
    monitor_write("\n\r    SerialNumber: ");
    monitor_write(CurDev->Info.SerialNumber);
    monitor_write("\n\r    Capacity: ");
    monitor_write_dec(CurDev->Info.CapacityLba / 2 / 1024);
    monitor_write(" MB");
  }
  else if(CurDev->Type==CC_DEVTYPE_NONE){
    monitor_write("\n\rDevice ");
    monitor_write_dec(Dev);
    monitor_write(" NOT FOUND");
  }
  else if(CurDev->Type==CC_DEVTYPE_ATAPI){
    monitor_write("\n\rDevice ");
    monitor_write_dec(Dev);
    monitor_write(" FOUND Type: ATAPI");
  }
  else{
    monitor_write("\n\rDevice ");
    monitor_write_dec(Dev);
    monitor_write(" FOUND Type: UNKNOWN");
  }
}

void ShowIdeSubData(){
  SelectAtaChannel(CC_PRIMARY);
  monitor_write("\n\rPRIMARY CHANNEL");
  ShowDeviceSubData(CC_DEV0);
  ShowDeviceSubData(CC_DEV1);
  monitor_write("\n\r");
  SelectAtaChannel(CC_SECONDARY);
  monitor_write("\n\rSECONDARY CHANNEL");
  ShowDeviceSubData(CC_DEV0);
  ShowDeviceSubData(CC_DEV1);
}


// ********************* ScanDevice *************************
// Initialize, reset and scan for all device in a channel
// The channel must be selected before calling this
// All information were stored in CurrentChannel global structure
// **********************************************************
int ScanDevice(int UseInterrupt){
  u8int DevCtrl;
  int Err=FALSE;

  // HDC_DEVC_HD15 is not needed in recent ata (is for compatibility)
  DevCtrl= HDC_DEVC_HD15 | ( UseInterrupt ? 0 : HDC_DEVC_NIEN );

  // Send To Device Control Register his Initialization Parameter
  OutPortAta(CC_DEVC, DevCtrl);

  // Try to chek for some sort of device before
  // execute some sort of command on it
  IdeDeviceDetection(CC_DEV0);
  IdeDeviceDetection(CC_DEV1);

  // select device 0
  SetDevBit(CC_DEV0);
  // Know that you know what devices exist you can
  // do a soft reset. The reset is for both device,
  // after the reset we will select Dev0 if possible
  Err=IdeSoftReset(FALSE, UseInterrupt);

  // Now we can issue command because we know how many devices
  // are on the channel and we have done the reset on they so:
  // is device really there? is it ATA or ATAPI?
  IdeDeviceTypeDetection(CC_DEV0);
  IdeDeviceTypeDetection(CC_DEV1);

  // Select first selectable device
  SetFirstDevBit();
  // take in mind that error from this function
  // are not critical, the caller can continue
  // to do his normal operation in respect
  // to DeviceType field of CurrentChannel->Device[Dev]
  return Err;
  // END: Now we have each device type in CurrentChannel
}


// ********************* IdentifyDevice *********************
// Execute Identify Device Command
// Store in Buffer the 256 u16int of Device Info
// Translate Buffer in DeviceInfo_Struct
// This sub works only on Ata device, to get information from 
// Atapi you should use IdentifyPacketDevice command
// **********************************************************
int IdentifyDevice(int Dev){
  int i;
  u16int Buffer[256];
  u16int *Tmp;
  int Err=0;
  DeviceInfo_Struct *TmpDev=(DeviceInfo_Struct *) & (CurrentChannel->Device[Dev].Info);
  // Be sure to reset the buffer
  /* memsetw(&Buffer, 0, 256) */
  asm volatile("cld\n" "rep stosw": :"D"(Buffer), "c"(256), "a"(0));
  asm("": : :"%edi", "%ecx");
  // Get 256 u16int of device info
  Err = IdePioDataInLba(Dev, HDC_CMD_IDENTIFY_DEVICE, 0, 0, 0L, (u16int *) &Buffer , 1, 0, TRUE);
  if( Err ){
    return Err;
  }
  // now the buffer contain raw u16int of info
  // we must translate it in a more readable struct
  TmpDev->Ata                     =(u8int) GETBITW(Buffer[0],15);
  TmpDev->Removable               =(u8int) GETBITW(Buffer[0],7);
  TmpDev->NotRemovable            =(u8int) GETBITW(Buffer[0],6);
  TmpDev->LogicalCylinders        =(u16int) Buffer[1];
  TmpDev->LogicalHeads            =(u16int) Buffer[3];
  TmpDev->LogicalSectorsPerTrack  =(u16int) Buffer[6];

  Tmp=(u16int *) &(TmpDev->SerialNumber);
  for(i=10;i<=19;i++){
    *Tmp=SWAPBYTEW(Buffer[i]);
    Tmp++;
  }
  TmpDev->SerialNumber[21]='\0';
  
  Tmp=(u16int *) &(TmpDev->FirmwareRev);
  for(i=23;i<=26;i++){
    *Tmp=SWAPBYTEW(Buffer[i]);
    Tmp++;
  }
  TmpDev->FirmwareRev[9]='\0';

  Tmp=(u16int *) &(TmpDev->ModelNumber);
  for(i=27;i<=46;i++){
    *Tmp=SWAPBYTEW(Buffer[i]);
    Tmp++;
  }
  TmpDev->ModelNumber[41]='\0';

  TmpDev->MaxMulitSectPerBlock    = (u8int) GETBYTEW(Buffer[47], 0);
  TmpDev->StandByTimerSupport     = (u8int) GETBITW(Buffer[49], 13);
  TmpDev->IORDYSupport            = (u8int) GETBITW(Buffer[49], 11);
  TmpDev->IORDYDisabled           = (u8int) GETBITW(Buffer[49], 10);        
  TmpDev->PioMode                 = (u8int) GETBYTEW(Buffer[51], 1);
  TmpDev->ValidUDMAMode           = (u8int) GETBITW(Buffer[53], 2);
  TmpDev->ValidCycleTime          = (u8int) GETBITW(Buffer[53], 1);
  TmpDev->ValidCurLogicalValue= (u8int) GETBITW(Buffer[53],0);
  TmpDev->CurLogicalCylinders = (u16int) Buffer[54];
  TmpDev->CurLogicalHeads     = (u16int) Buffer[55];
  TmpDev->CurLogicalSectorsPerTrack = (u16int) Buffer[56];
  TmpDev->CapacityInSectors   = (u32int) MAKEDWORDW(Buffer[58], Buffer[57]);
  TmpDev->ValidCurMultiSectPerInt  = (u8int) GETBITW(Buffer[59], 8);
  TmpDev->CurMultiSectPerInt  = (u8int) GETBYTEW(Buffer[59], 0);
  TmpDev->CapacityLba         = (u32int) MAKEDWORDW(Buffer[61], Buffer[60]);

  TmpDev->MultiDMASupported = ((u8int) GETBYTEW(Buffer[63], 1)) & 0x07; // only 3 least sig bit
  TmpDev->MultiDMASelected  = ((u8int) GETBYTEW(Buffer[63], 0)) & 0x07; // only 3 least sig bit

  TmpDev->AdvPioModeSupported = (u8int) GETBYTEW(Buffer[64],0);
  TmpDev->MinCycleTime        = (u16int) Buffer[65];
  TmpDev->RecCycleTime        = (u16int) Buffer[66];
  TmpDev->MinPioCycleTime     = (u16int) Buffer[67];
  TmpDev->MinPioCyleTimeFlow  = (u16int) Buffer[68];
  TmpDev->QueueDepth          = (u8int) GETBYTEW(Buffer[75],0) & 0x1F;
  
  TmpDev->AtaSupported        = (u16int) Buffer[80];

  i=14;
  while(i>0 && (GETBITW(Buffer[80],i)==0)){
    i--;
  }

  TmpDev->HighestAtaSupported=(u8int) i;

  if(Buffer[81]==0xFFFF){
    TmpDev->MinorVersion    = (u16int) Buffer[81];
  }
  else{
    TmpDev->MinorVersion    = (u16int) Buffer[81];
  }
  
  TmpDev->SFSNopSupported            = (u8int) GETBITW(Buffer[82],14);
  TmpDev->SFSReadBufferSupported     = (u8int) GETBITW(Buffer[82],13);
  TmpDev->SFSWriteBufferSupported    = (u8int) GETBITW(Buffer[82],12);
  TmpDev->SFSProtectedAreaSupported  = (u8int) GETBITW(Buffer[82],10);
  TmpDev->SFSDeviceResetSupported    = (u8int) GETBITW(Buffer[82],9);
  TmpDev->SFSServiceIntSupported     = (u8int) GETBITW(Buffer[82],8);
  TmpDev->SFSReleaseIntSupported     = (u8int) GETBITW(Buffer[82],7);
  TmpDev->SFSLookAheadSupported      = (u8int) GETBITW(Buffer[82],6);
  TmpDev->SFSWriteCacheSupported     = (u8int) GETBITW(Buffer[82],5);
  TmpDev->SFSPacketSupported         = (u8int) GETBITW(Buffer[82],4);
  TmpDev->SFSPowerManagSupported     = (u8int) GETBITW(Buffer[82],3);
  TmpDev->SFSRemovableMediaSupported = (u8int) GETBITW(Buffer[82],2);
  TmpDev->SFSSecurityModeSupported   = (u8int) GETBITW(Buffer[82],1);
  TmpDev->SFSSmartSupported          = (u8int) GETBITW(Buffer[82],0);
  TmpDev->SFSRemMediaNotifSupported  = (u8int) GETBITW(Buffer[83],4);
  TmpDev->SFSAdvPowerManagSupported  = (u8int) GETBITW(Buffer[83],3);
  TmpDev->SFSCFASupported            = (u8int) GETBITW(Buffer[83],2);
  TmpDev->SFSRWDmaQueuedSupported    = (u8int) GETBITW(Buffer[83],1);
  TmpDev->SFSDownMicrocodeSupported  = (u8int) GETBITW(Buffer[83],1);

  TmpDev->SFEServiceIntEnalbed       = (u8int) GETBITW(Buffer[85],8);
  TmpDev->SFEReleaseIntEnabled       = (u8int) GETBITW(Buffer[85],7);
  TmpDev->SFELookAheadEnabled        = (u8int) GETBITW(Buffer[85],6);
  TmpDev->SFEWriteCacheEnabled       = (u8int) GETBITW(Buffer[85],5);
  TmpDev->SFESecurityModeEnabled     = (u8int) GETBITW(Buffer[85],1);
  TmpDev->SFESmartEnabled            = (u8int) GETBITW(Buffer[85],0);
  TmpDev->SFERemMediaNotifEnabled    = (u8int) GETBITW(Buffer[86],4);
  TmpDev->SFEAdvPowerManagEnabled    = (u8int) GETBITW(Buffer[86],3);

  TmpDev->UDMASelected = ((u8int) GETBYTEW(Buffer[88],1)) & 0x3F;
  TmpDev->UDMASupported =((u8int) GETBYTEW(Buffer[88],0)) & 0x3F;
  
  i=5;
  while(i>=0 && (GETBITW(Buffer[88],i)==0)){
    i--;
  }

  TmpDev->HighestUDMASupported=(u8int) i;

  TmpDev->SecurityEraseTime    = (u16int) Buffer[89];
  TmpDev->SecurityEnEraseTime  = (u16int) Buffer[90];
  TmpDev->CurAPMValue          = (u16int) Buffer[91];

  TmpDev->SecurityLevel        = (u8int) GETBITW(Buffer[128],8);
  TmpDev->SecurityEnErase      = (u8int) GETBITW(Buffer[128],5);
  TmpDev->SecurityCountExpired = (u8int) GETBITW(Buffer[128],4);
  TmpDev->SecurityFrozen       = (u8int) GETBITW(Buffer[128],3);
  TmpDev->SecurityLocked       = (u8int) GETBITW(Buffer[128],2);
  TmpDev->SecurityEnabled      = (u8int) GETBITW(Buffer[128],1);
  TmpDev->SecuritySupported    = (u8int) GETBITW(Buffer[128],0);

  Tmp=(u16int *) &(TmpDev->VendorSpecific);
  for(i=129;i<=159;i++){
    *Tmp=(u16int) Buffer[i];
    Tmp++;
  }
  return 0;
}


void ShowDeviceDataRowName(char * Name,int Col){
  monitor_write(Name);
  monitor_write("=");
}


void ShowDeviceDataRowValue(char * Name, int Col, char * Format, u32int Value){
  ShowDeviceDataRowName(Name,Col);
  monitor_write(Format);
  monitor_write_dec(Value);
}

void ShowDeviceDataRowString(char * Name, int Col, char * Value){
  ShowDeviceDataRowName(Name,Col);
  monitor_write(Value);
}


void ShowDeviceDataRowSup(char * Name,int Col, u8int Supported){
  ShowDeviceDataRowName(Name,Col);
  monitor_write("Supported:");
  monitor_write(Bit2YesNo(Supported));
}

void ShowDeviceDataRowSupEn(char * Name,int Col,u8int Supported,u8int Enabled){
  ShowDeviceDataRowName(Name,Col);
  monitor_write("Supported:");
  monitor_write(Bit2YesNo(Supported));
  monitor_write("  -  ");
  monitor_write("Enabled:");
  monitor_write(Bit2YesNo(Enabled));
}

void ShowDeviceDataRowBitNum(u16int BitCode,u8int StartFrom, u8int EndTo, u8int StartPrintNum){
  int i;
  u8int Val=BitCode;

  if(StartFrom){
    Val=Val >> StartFrom;
  }

  for(i=0;i<=EndTo-StartFrom;i++){
    if (Val & 0x01){
      monitor_write_hex(StartPrintNum+i);
    }
    Val=Val >> 1;
  }
}


void ShowDeviceData(int Dev,int Col){
  DeviceInfo_Struct * TmpDev=(DeviceInfo_Struct *) &(CurrentChannel->Device[Dev].Info);

  monitor_write("\n\r***** GENERAL INFORMATION *****");
  ShowDeviceDataRowString("\n\rModel Name",Col,TmpDev->ModelNumber);      
  ShowDeviceDataRowString("\n\rFirmware Revision",Col,TmpDev->FirmwareRev);
  ShowDeviceDataRowString("\n\rSerial Number",Col,TmpDev->SerialNumber);

  ShowDeviceDataRowName("\n\rType",Col);
  if(CurrentChannel->Device[Dev].Type==CC_DEVTYPE_ATA){
    monitor_write("ATA");
  }
  else if(CurrentChannel->Device[Dev].Type==CC_DEVTYPE_ATAPI){
    monitor_write("ATAPI");
  }
  else if(CurrentChannel->Device[Dev].Type==CC_DEVTYPE_UNKN){
    monitor_write("UNKNOW");
  }
  if(TmpDev->Removable){
    monitor_write(" - Removable");
  }
  if(TmpDev->NotRemovable){
    monitor_write(" - Not Removable");
  }

  monitor_write("\n\r\n\r***** STANDARD SUPPORTED AND SELECTED *****");

  ShowDeviceDataRowName("\n\rAta Supported",Col); 
  if((TmpDev->AtaSupported == 0x0000) || (TmpDev->AtaSupported == 0xFFFF)){
    monitor_write("UNKNOW");
  }
  else{
    // bit 0 is reserved
    ShowDeviceDataRowBitNum(TmpDev->AtaSupported,1,14,1);
  }
  ShowDeviceDataRowName("\n\rUdma Supported",Col);        
  if(TmpDev->ValidUDMAMode){
    if(TmpDev->UDMASupported){
      // Udma star from 0
      ShowDeviceDataRowBitNum((u16int) TmpDev->UDMASupported,0,7,0);    
    }
    else{
      monitor_write("NONE");
    }
  }
  else{
    monitor_write("UNKNOW");
  }


  ShowDeviceDataRowName("\n\rUdma Selected",Col);
  if(TmpDev->ValidUDMAMode ){
    if(TmpDev->UDMASelected){
      ShowDeviceDataRowBitNum((u16int) TmpDev->UDMASelected,0,7,0);  
    }
    else{
      monitor_write("NONE");
    }
  }
  else{
    monitor_write("UNKNOW");
  }

  ShowDeviceDataRowName("\n\rMultiDma Supported",Col);
  if(TmpDev->MultiDMASupported){
    ShowDeviceDataRowBitNum((u16int) TmpDev->UDMASupported,0,2,0);
  }
  else{
    monitor_write("NONE");
  }

  ShowDeviceDataRowName("\n\rMultiDma Selected",Col);
  if(TmpDev->MultiDMASelected){
    ShowDeviceDataRowBitNum((u16int) TmpDev->UDMASelected,0,2,0); 
  }
  else{
    monitor_write("NONE");
  }

  ShowDeviceDataRowValue("\n\rStandard Pio Mode",Col,"%d",TmpDev->PioMode);

  ShowDeviceDataRowName("\n\rAdvanced Pio Mode Supported",Col);   
  if(TmpDev->AdvPioModeSupported){
    ShowDeviceDataRowBitNum(TmpDev->AdvPioModeSupported,0,7,3);  
  }
  else{
    monitor_write("NONE");
  }
  
  WaitKeyPress(MSG_PRESSKEY);     

  monitor_write("\n\r\n\r***** DEVICE LOGICAL INFORMATION *****");
  ShowDeviceDataRowValue("\n\rLogical Cylinders",Col,"%u",TmpDev->LogicalCylinders);
  ShowDeviceDataRowValue("\n\rLogical Heads",Col,"%u",TmpDev->LogicalHeads);
  ShowDeviceDataRowValue("\n\rLogical Sectors",Col,"%u",TmpDev->LogicalSectorsPerTrack);
  if(TmpDev->ValidCurLogicalValue){
    ShowDeviceDataRowValue("\n\rCurrent Logical Cylinders",Col, "%u",TmpDev->CurLogicalCylinders);
    ShowDeviceDataRowValue("\n\rCurrent Logical Heads",Col,"%u",TmpDev->CurLogicalHeads);
    ShowDeviceDataRowValue("\n\rCurrent Logical Sectors",Col,"%u",TmpDev->CurLogicalSectorsPerTrack);
  }
  else{
    ShowDeviceDataRowString("\n\rCurrent Logical Cylinders",Col,"UNKNOW");
    ShowDeviceDataRowString("\n\rCurrent Logical Heads",Col,"UNKNOW");
    ShowDeviceDataRowString("\n\rCurrent Logical Sectors",Col,"UNKNOW");
  }
  ShowDeviceDataRowValue("\n\rCapacity Sectors Current CHS",Col,"%u",TmpDev->CapacityInSectors);
  ShowDeviceDataRowValue("\n\rCapacity Sectors",Col,"%u",TmpDev->CapacityLba);
  ShowDeviceDataRowValue("\n\rCapacity in MB",Col,"%u",TmpDev->CapacityLba / 2 / 1024);

  ShowDeviceDataRowSupEn("\n\rIORDY",Col,TmpDev->IORDYSupport,TmpDev->IORDYDisabled);
  
  WaitKeyPress(MSG_PRESSKEY);     

  monitor_write("\n\r\n\r***** DEVICE FEATURES AND SETTING INFORMATION *****");
  ShowDeviceDataRowSup("\n\rR W Dma Queued",Col,TmpDev->SFSRWDmaQueuedSupported);
  ShowDeviceDataRowValue("\n\rQueue Depth",Col,"%u",TmpDev->QueueDepth);
  ShowDeviceDataRowValue("\n\rMax Sect Per Block (in Multi)",Col,"%u",TmpDev->MaxMulitSectPerBlock);
  ShowDeviceDataRowSupEn("\n\rAdv Power Management",Col,TmpDev->SFSAdvPowerManagSupported,TmpDev->SFEAdvPowerManagEnabled);
  ShowDeviceDataRowValue("\n\rAdv Power Management Level",Col,"%u",TmpDev->CurAPMValue);

  ShowDeviceDataRowSupEn("\n\rLook Ahead",Col,TmpDev->SFSLookAheadSupported,TmpDev->SFELookAheadEnabled);
  ShowDeviceDataRowSupEn("\n\rRelease Interrupt",Col,TmpDev->SFSReleaseIntSupported,TmpDev->SFEReleaseIntEnabled);
  ShowDeviceDataRowSupEn("\n\rRemovable Media Notif",Col,TmpDev->SFSRemMediaNotifSupported,TmpDev->SFERemMediaNotifEnabled);
  ShowDeviceDataRowSupEn("\n\rService Interrupt",Col,TmpDev->SFSServiceIntSupported,TmpDev->SFEServiceIntEnalbed);
  ShowDeviceDataRowSupEn("\n\rSmart",Col,TmpDev->SFSSmartSupported,TmpDev->SFESmartEnabled);
  ShowDeviceDataRowSupEn("\n\rWrite Cache",Col,TmpDev->SFSWriteCacheSupported,TmpDev->SFEWriteCacheEnabled);
  ShowDeviceDataRowSup("\n\rRead Buffer",Col,TmpDev->SFSReadBufferSupported);
  ShowDeviceDataRowSup("\n\rWrite Buffer",Col,TmpDev->SFSWriteBufferSupported);
  ShowDeviceDataRowSup("\n\rNop",Col,TmpDev->SFSNopSupported);
  ShowDeviceDataRowSup("\n\rPacket",Col,TmpDev->SFSPacketSupported);
  ShowDeviceDataRowSup("\n\rPower Management",Col,TmpDev->SFSPowerManagSupported);
  ShowDeviceDataRowSup("\n\rProtected Area",Col,TmpDev->SFSProtectedAreaSupported);
  ShowDeviceDataRowSup("\n\rDownload Microcode",Col,TmpDev->SFSDownMicrocodeSupported);
  ShowDeviceDataRowSup("\n\rCFA",Col,TmpDev->SFSCFASupported);
  ShowDeviceDataRowSup("\n\rDevice Reset",Col,TmpDev->SFSDeviceResetSupported);
  ShowDeviceDataRowSup("\n\rStandBy Timer",Col,TmpDev->StandByTimerSupport);

  WaitKeyPress(MSG_PRESSKEY);     


  monitor_write("\n\r\n\r***** DEVICE TIMING INFORMATION *****");
  ShowDeviceDataRowSup("\n\rStandBy Timer",Col,TmpDev->StandByTimerSupport);
  
  if(TmpDev->ValidCycleTime){
    ShowDeviceDataRowValue("\n\rMin Multi Dma Cycle Time (ns)",Col,"%u",TmpDev->MinCycleTime);
    ShowDeviceDataRowValue("\n\rRecc MultiDma Cycle Time (ns)",Col,"%u",TmpDev->RecCycleTime);
    ShowDeviceDataRowValue("\n\rMin Pio Cycle Time (ns)",Col,"%u",TmpDev->MinPioCycleTime);
    ShowDeviceDataRowValue("\n\rMin Pio Cycle Time Flow (ns)",Col,"%u",TmpDev->MinPioCyleTimeFlow);
  }
  else{
    monitor_write("\n\rTiming Information Unavaiable");
  }

  monitor_write("\n\r\n\r***** SECURITY INFORMATION *****");
  ShowDeviceDataRowSupEn("\n\rSecurity",Col,TmpDev->SecuritySupported,TmpDev->SecurityEnabled);
  ShowDeviceDataRowSupEn("\n\rSecurity Mode",Col,TmpDev->SFSSecurityModeSupported,TmpDev->SFESecurityModeEnabled);
  ShowDeviceDataRowValue("\n\rSecurity Erase Time (min)",Col,"%u",(int) TmpDev->SecurityEraseTime*2);
  ShowDeviceDataRowValue("\n\rEnh Security Erase Time (min)",Col,"%u",(int) TmpDev->SecurityEnEraseTime*2);
  
  ShowDeviceDataRowName("\n\rSecurity Level",Col);        
  if(TmpDev->SFESecurityModeEnabled){
    if(TmpDev->SecurityLevel){
      monitor_write("Max");
    }
    else{
      monitor_write("High");
    }
  }
  else{
    monitor_write("Disabled");
  }

  ShowDeviceDataRowString("\n\rSecurity Frozen",Col,Bit2YesNo(TmpDev->SecurityFrozen));
  monitor_write("\n\rSecurity CountExpired=");
  monitor_write(Bit2YesNo(TmpDev->SecurityCountExpired));
  monitor_write("\n\rSecurity Locked=");
  monitor_write(Bit2YesNo(TmpDev->SecurityLocked));
  ShowDeviceDataRowSup("\n\rSecurity Enh Erase Supported",Col,TmpDev->SecurityEnErase);

  monitor_write("\n\r\n\r END DEVICE INFORMATION \n\r");
}



// ************************ InitIde *************************
// Initialization of the driver.
// Prepare data structure, check fo device on each channel
// and fill structure with channel and device info
// **********************************************************
void init_ide(){

  // --- modified by: Andrea Righi -------------------------------//
  // Install the IRQ handlers for both IDE channels               //
  register_interrupt_handler(IRQ14, &Ide_Handler_Pri);
  register_interrupt_handler(IRQ15, &Ide_Handler_Sec);
  // -------------------------------------------------------------//
  // Initialize structure for primary channel
  SelectAtaChannel(CC_PRIMARY);
  SetAtaRegisterIoPort(HDC_BASEPRI,HDC_BASEPRI+HDC_CONTROLGAP,HDC_INTPRI);
  // Initialize devices
  ScanDevice(TRUE);
  if(CurrentChannel->Device[CC_DEV0].Type==CC_DEVTYPE_ATA){
    IdentifyDevice(CC_DEV0);
  }
  if(CurrentChannel->Device[CC_DEV1].Type==CC_DEVTYPE_ATA){
    IdentifyDevice(CC_DEV1);
  }
  // Initialize structure for secondary channel
  SelectAtaChannel(CC_SECONDARY);
  SetAtaRegisterIoPort(HDC_BASESEC,HDC_BASESEC+HDC_CONTROLGAP,HDC_INTSEC);
  // Initialize devices
  ScanDevice(TRUE);
  if(CurrentChannel->Device[CC_DEV0].Type==CC_DEVTYPE_ATA){
    IdentifyDevice(CC_DEV0);
  }
  if(CurrentChannel->Device[CC_DEV1].Type==CC_DEVTYPE_ATA){
    IdentifyDevice(CC_DEV1);
  }
}



// ******************** ReadSectorsLba **********************
// Read one or more sector of data from hd
// **********************************************************
int ReadSectorsLba(int Dev, u32int Lba, int NumSect, u16int * Buffer,int UseInterrupt){
  return IdePioDataInLba(Dev,HDC_CMD_READ_SECTORS,0,NumSect,Lba,Buffer,NumSect,1,UseInterrupt);
}

// ******************** WriteSectorsLba *********************
// Write one or more sector of data from hd
// **********************************************************
int WriteSectorsLba(int Dev, u32int Lba, int NumSect, u16int * Buffer,int UseInterrupt){
  return IdePioDataOutLba(Dev,HDC_CMD_WRITE_SECTORS,0,NumSect,Lba,Buffer,NumSect,1,UseInterrupt);
}

